package com.ylr.admin.framework.service.impl;

import com.ylr.admin.common.dto.dept.DeptDto;
import com.ylr.admin.common.dto.dept.DeptEnumDto;
import com.ylr.admin.common.enums.DeptEnum;
import com.ylr.admin.common.vo.dept.DeptFormVo;
import com.ylr.admin.common.vo.dept.DeptVo;
import com.ylr.admin.framework.entity.DeptEntity;
import com.ylr.admin.framework.mapper.DeptMapper;
import com.ylr.admin.framework.service.DeptService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylr.base.common.constant.Constant;
import com.ylr.base.common.dto.PageDto;
import com.ylr.base.common.enums.CommonEnum;
import com.ylr.base.common.enums.ResultEnum;
import com.ylr.base.common.exception.YlrException;
import com.ylr.base.common.po.user.UserPo;
import com.ylr.base.common.utils.ThrottleUtils;
import com.ylr.base.common.utils.UserUtils;
import com.ylr.base.common.vo.UpdateStatusVo;
import com.ylr.base.framework.service.AsyncService;
import com.ylr.base.framework.service.SnowflakeService;
import com.ylr.config.common.enums.KeyEnum;
import com.ylr.config.framework.resolver.YcMappingResolver;
import com.ylr.redis.framework.service.RedisService;
import com.ylr.redis.framework.service.RedisStringService;
import com.ylr.redis.framework.service.RedissonService;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by IntelliJ IDEA.
 *
 * @author wyw
 * date: 2023-04-21 11:27:23
 * className: DeptServiceImpl
 * version: 1.0
 * description:
 */
@Service("deptService")
@AllArgsConstructor
public class DeptServiceImpl extends ServiceImpl<DeptMapper, DeptEntity> implements DeptService {

    private static final Logger log = LoggerFactory.getLogger(DeptServiceImpl.class);

    private final YcMappingResolver ycMappingResolver;

    private final SnowflakeService snowflakeService;

    private final AsyncService asyncService;

    private final RedisStringService redisStringService;

    private final RedisService redisService;

    private final RedissonService redissonService;

    private final ThrottleUtils throttleUtils;

    @Override
    public void saveDept(DeptVo deptVo) {
        // 获取正在保存部门的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        DeptEntity dept = this.newDept(deptVo, userPo, date);
        // 插入数据
        baseMapper.insert(dept);
        log.info("部门插入完成");

    }

    @Override
    public PageDto<DeptDto> pageDeptList(DeptFormVo deptFormVo) {
        LambdaQueryWrapper<DeptEntity> deptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 匹配条件
        deptLambdaQueryWrapper.eq(Objects.nonNull(deptFormVo.getParentId()), DeptEntity::getParentId, deptFormVo.getParentId())
                .eq(Objects.nonNull(deptFormVo.getLevel()), DeptEntity::getLevel, deptFormVo.getLevel())
                .eq(Objects.nonNull(deptFormVo.getStatus()), DeptEntity::getStatus, deptFormVo.getStatus())
                .like(Objects.nonNull(deptFormVo.getWord()), DeptEntity::getDeptName, deptFormVo.getWord())
                .eq(DeptEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 查询数据
        List<DeptEntity> deptList = baseMapper.selectList(deptLambdaQueryWrapper);
        if (deptList.isEmpty()) {
            log.info("部门列表查询结果为空");
            return new PageDto<>();
        }

        List<DeptDto> deptDtoList = new ArrayList<>();
        Map<String, DeptDto> deptMap = new HashMap<>();
        List<DeptDto> lastOptList = new ArrayList<>();
        for (DeptEntity dept : deptList) {
            // 部门数据封装
            DeptDto deptDto = this.getDeptDto(dept);

            deptMap.put(deptDto.getId(), deptDto);

            // 查找父部门
            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                if (CommonEnum.DEFAULT_ID.getStringValue().equals(deptDto.getParentId())) {
                    // 一级部门
                    deptDtoList.add(deptDto);
                    continue;
                }
                // 找不到父部门，延后处理
                lastOptList.add(deptDto);
            }
            parentDeptDto.getChildren().add(deptDto);
        }
        for (DeptDto deptDto : lastOptList) {
            // 查找父部门
            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                // 仍未找到父部门，直接加到结果列表中
                deptDtoList.add(deptDto);
                continue;
            }
            parentDeptDto.getChildren().add(deptDto);
        }
        deptDtoList.sort(Comparator.comparing(DeptDto::getSort).thenComparing(DeptDto::getCreateTime).thenComparing(DeptDto::getId));

        // 分页操作
        return PageDto.pageDtoBuild(deptDtoList, deptFormVo.getPageNo(), deptFormVo.getPageSize());
    }

    @Override
    public DeptDto getDept(Long id) {
        // 获取部门
        DeptEntity dept = findDept(id);

        return this.getDeptDto(dept);
    }

    @Override
    public Integer getNextSort(Long parentId) {
        // 查询数据
        Integer maxSort = baseMapper.selectMaxSort(parentId, CommonEnum.DELETE_NO.getValue());
        if (Objects.isNull(maxSort)) {
            maxSort = 0;
        }
        return maxSort + 1;
    }

    @Override
    public DeptDto getDeptTree() {

        DeptDto topDeptDto = new DeptDto();
        topDeptDto.setId(CommonEnum.DEFAULT_ID.getStringValue())
                .setParentPath(StringUtils.EMPTY)
                .setDeptName("顶级部门")
                .setChildren(new TreeSet<>());

        LambdaQueryWrapper<DeptEntity> deptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        deptLambdaQueryWrapper.select(DeptEntity::getId, DeptEntity::getParentId, DeptEntity::getParentPath, DeptEntity::getDeptName,
                DeptEntity::getSort, DeptEntity::getCreateTime);
        // 匹配条件
        deptLambdaQueryWrapper.eq(DeptEntity::getStatus, CommonEnum.STATUS_USE.getValue())
                .eq(DeptEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 查询数据
        List<DeptEntity> deptList = baseMapper.selectList(deptLambdaQueryWrapper);
        if (deptList.isEmpty()) {
            log.info("有效部门数据为空");
            return topDeptDto;
        }

        Map<String, DeptDto> deptMap = new HashMap<>();
        List<DeptDto> lastOptList = new ArrayList<>();

        deptMap.put(topDeptDto.getId(), topDeptDto);

        for (DeptEntity dept : deptList) {
            // 数据封装
            DeptDto deptDto = this.getDeptDto(dept);

            deptMap.put(deptDto.getId(), deptDto);

            // 查找父部门
            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                // 找不到父部门，延后处理
                lastOptList.add(deptDto);
            }
            // 子部门放入父部门的集合中
            parentDeptDto.getChildren().add(deptDto);
        }
        for (DeptDto deptDto : lastOptList) {
            // 查找父部门
            DeptDto parentUriDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentUriDto)) {
                log.warn("查找父部门找不到。{}", deptDto);
                continue;
            }
            parentUriDto.getChildren().add(deptDto);
        }

        return topDeptDto;
    }

    @Override
    public List<DeptDto> getParentDeptList(Long id, Integer order) {
        // 获取部门
        DeptEntity dept = findDept(id);

        List<Long> deptIdList = Stream.of(dept.getParentPath().split(Constant.SPLIT))
                .map(Long::parseLong)
                .collect(Collectors.toList());
        // 批量查询部门
        List<DeptEntity> deptList = baseMapper.selectBatchIds(deptIdList);
        /*
            查询出来的结果已按照顶级父级到直接父级的方式排序
         */
        if (Constant.ONE.equals(order)) {
            // 排序操作
            Collections.reverse(deptList);
        }

        return deptList.stream().map(this::getDeptDto).collect(Collectors.toList());
    }

    @Override
    public List<DeptDto> getChildrenDeptTree(Long parentId) {

        LambdaQueryWrapper<DeptEntity> deptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        deptLambdaQueryWrapper.select(DeptEntity::getId, DeptEntity::getParentId, DeptEntity::getParentPath, DeptEntity::getDeptName,
                DeptEntity::getSort, DeptEntity::getCreateTime);
        // 匹配条件
        deptLambdaQueryWrapper.eq(DeptEntity::getId, parentId)
                .eq(DeptEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 查询数据
        List<DeptEntity> deptList = baseMapper.selectList(deptLambdaQueryWrapper);
        if (deptList.isEmpty()) {
            log.warn("父部门数据不存在");
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
        DeptDto parentDept = this.getDeptDto(deptList.get(0));

        deptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 查询字段
        deptLambdaQueryWrapper.select(DeptEntity::getId, DeptEntity::getParentId, DeptEntity::getParentPath, DeptEntity::getDeptName,
                DeptEntity::getSort, DeptEntity::getCreateTime);
        // 匹配条件
        deptLambdaQueryWrapper.likeRight(DeptEntity::getParentPath, parentDept.getParentPath() + parentDept.getId() + Constant.SPLIT)
                .eq(DeptEntity::getStatus, CommonEnum.STATUS_USE.getValue())
                .eq(DeptEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 查询数据
        deptList = baseMapper.selectList(deptLambdaQueryWrapper);
        if (deptList.isEmpty()) {
            log.info("子部门数据为空");
            return Collections.emptyList();
        }

        Map<String, DeptDto> deptMap = new HashMap<>();
        List<DeptDto> lastOptList = new ArrayList<>();

        deptMap.put(parentDept.getId(), parentDept);

        for (DeptEntity dept : deptList) {
            // 数据封装
            DeptDto deptDto = this.getDeptDto(dept);

            deptMap.put(deptDto.getId(), deptDto);

            // 查找父部门
            DeptDto parentDeptDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentDeptDto)) {
                // 找不到父部门，延后处理
                lastOptList.add(deptDto);
            }
            // 子部门放入父部门的集合中
            parentDeptDto.getChildren().add(deptDto);
        }
        for (DeptDto deptDto : lastOptList) {
            // 查找父部门
            DeptDto parentUriDto = deptMap.get(deptDto.getParentId());
            if (Objects.isNull(parentUriDto)) {
                log.warn("查找父部门找不到。{}", deptDto);
                continue;
            }
            parentUriDto.getChildren().add(deptDto);
        }

        return Collections.singletonList(parentDept);
    }

    @Override
    public DeptEnumDto getPageEnums() {

        DeptEnumDto deptEnumDto = new DeptEnumDto();
        deptEnumDto.setLevelEnumList(DeptEnum.getLevelEnumList());
        deptEnumDto.setStatusEnumList(CommonEnum.getStatusEnumList());

        return deptEnumDto;
    }

    @Override
    public Map<String, String> getDeptNameMap(Set<Long> deptIdSet) {
        if (deptIdSet.isEmpty()) {
            log.info("部门主键集合为空");
            return Collections.emptyMap();
        }
        LambdaQueryWrapper<DeptEntity> deptLambdaQueryWrapper = new LambdaQueryWrapper<>();
        // 1、查询字段
        deptLambdaQueryWrapper.select(DeptEntity::getId, DeptEntity::getDeptName);
        // 2、匹配条件
        deptLambdaQueryWrapper.in(DeptEntity::getId, deptIdSet)
                .eq(DeptEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 3、查询数据
        List<DeptEntity> deptList = baseMapper.selectList(deptLambdaQueryWrapper);
        // 4、数据转换
        return deptList.stream().collect(Collectors.toMap(dept -> dept.getId().toString(), DeptEntity::getDeptName));
    }

    @Transactional
    @Override
    public void updateDept(DeptVo deptVo) {
        // 1、获取部门对象
        DeptEntity dept = this.findDept(deptVo.getId());

        // 获取正在修改部门的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        boolean updateParent = false;

        DeptEntity _dept = new DeptEntity();
        _dept.setId(deptVo.getId())
            .setParentId(deptVo.getParentId())
            .setDeptName(deptVo.getDeptName())
            .setCode(deptVo.getCode())
            .setLevel(deptVo.getLevel())
            .setSort(deptVo.getSort())
            .setUpdateTime(date)
            .setUpdateUser(userPo.getUsername())
            .setUpdateUserId(userPo.getId());
        if (dept.getParentId().equals(deptVo.getParentId())) {
            // 更新父级部门路径
            _dept.setParentPath(deptVo.getParentPath() + deptVo.getParentId() + Constant.SPLIT);

            updateParent = true;
        }
        // 2、更新数据
        baseMapper.updateById(_dept);
        log.info("部门更新完成");

        // 3、更新子部门数据
        if (updateParent) {
            String path = dept.getParentPath() + dept.getId() + Constant.SPLIT;
            // 查询子部门列表
            List<DeptEntity> deptList = baseMapper.selectChildrenList(path, CommonEnum.DELETE_NO.getValue());
            if (deptList.isEmpty()) {
                log.info("子部门数据为空，无需进行操作");
                return;
            }

            List<DeptEntity> updateDeptList = new ArrayList<>(deptList.size());
            for (DeptEntity deptEntity : deptList) {
                String parentPath = deptEntity.getParentPath();
                // 替换父级部门路径
                parentPath = parentPath.replaceFirst(dept.getParentPath(), _dept.getParentPath());

                DeptEntity updateDept = new DeptEntity();
                updateDept.setId(deptEntity.getId())
                        .setParentPath(parentPath)
                        .setUpdateTime(date)
                        .setUpdateUser(userPo.getUsername())
                        .setUpdateUserId(userPo.getId());
                // 记录数据
                updateDeptList.add(updateDept);
            }
            // 批量更新部门
            this.updateBatchById(updateDeptList);
        }

    }

    @Override
    public void updateDeptStatus(UpdateStatusVo updateStatusVo) {
        // 获取正在修改部门状态的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        LambdaUpdateWrapper<DeptEntity> deptLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置字段值
        deptLambdaUpdateWrapper.set(DeptEntity::getStatus, updateStatusVo.getStatus())
                .set(DeptEntity::getUpdateTime, date)
                .set(DeptEntity::getUpdateUser, userPo.getUsername())
                .set(DeptEntity::getUpdateUserId, userPo.getId());
        // 匹配条件
        deptLambdaUpdateWrapper.in(DeptEntity::getId, updateStatusVo.getIdList())
                .eq(DeptEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 更新数据
        int count = baseMapper.update(null, deptLambdaUpdateWrapper);
        log.info("修改部门状态完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
    }

    @Override
    public void deleteDept(List<Long> idList) {

        // 校验删除数量是否超过最大阈值
        Integer batchMax = ycMappingResolver.getValue(KeyEnum.BATCH_OPT_NUM.getKey(), Integer.class);
        if (batchMax < idList.size()) {
            log.warn("一次删除接口数量超过阈值。batchMax={} idListSize={}", batchMax, idList.size());
            throw new YlrException(ResultEnum.BATCH_FAIL);
        }

        // 获取正在删除部门的用户对象
        UserPo userPo = UserUtils.getUser();
        Date date = new Date();

        LambdaUpdateWrapper<DeptEntity> deptLambdaUpdateWrapper = new LambdaUpdateWrapper<>();
        // 设置字段值
        deptLambdaUpdateWrapper.set(DeptEntity::getDeleteStatus, CommonEnum.DELETE_YES.getValue())
                .set(DeptEntity::getUpdateTime, date)
                .set(DeptEntity::getUpdateUser, userPo.getUsername())
                .set(DeptEntity::getUpdateUserId, userPo.getId());
        // 匹配条件
        deptLambdaUpdateWrapper.in(DeptEntity::getId, idList)
                .eq(DeptEntity::getDeleteStatus, CommonEnum.DELETE_NO.getValue());
        // 更新数据
        int count = baseMapper.update(null, deptLambdaUpdateWrapper);
        log.info("删除部门完成。count={}", count);
        if (count == 0) {
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
    }

    /**
     * 查询部门
     * @param id 部门主键
     * @return 部门实体对象
     */
    private DeptEntity findDept(Long id) {
        // 查询数据
        DeptEntity dept = baseMapper.selectById(id);
        if (Objects.isNull(dept)) {
            log.warn("部门不存在");
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
        if (CommonEnum.DELETE_YES.getValue().equals(dept.getDeleteStatus())) {
            log.warn("部门已被删除");
            throw new YlrException(ResultEnum.NOT_FOUND);
        }
        return dept;
    }

    /**
     * 部门参数转化成部门实体对象
     * @param deptVo 参数对象
     * @return 部门实体对象
     */
    private DeptEntity newDept(DeptVo deptVo, UserPo userPo, Date date) {
        DeptEntity dept = new DeptEntity();
        dept.setId(snowflakeService.getId())
            .setParentId(deptVo.getParentId())
            .setParentPath(deptVo.getParentPath() + deptVo.getParentId() + Constant.SPLIT)
            .setDeptName(deptVo.getDeptName())
            .setCode(deptVo.getCode())
            .setLevel(deptVo.getLevel())
            .setSort(deptVo.getSort())
            .setStatus(CommonEnum.STATUS_USE.getValue())
            .setDeleteStatus(CommonEnum.DELETE_NO.getValue())
            .setUpdateTime(date)
            .setUpdateUser(userPo.getUsername())
            .setUpdateUserId(userPo.getId())
            .setCreateTime(date)
            .setCreateUser(userPo.getUsername())
            .setCreateUserId(userPo.getId());
        return dept;
    }

    /**
     * 部门实体对象封装
     * @param dept 部门对象
     * @return 封装结果
     */
    private DeptDto getDeptDto(DeptEntity dept) {
        DeptDto deptDto = new DeptDto();
        deptDto.setId(dept.getId().toString())
                .setParentId(dept.getParentId().toString())
                .setParentPath(dept.getParentPath())
                .setDeptName(dept.getDeptName())
                .setCode(dept.getCode())
                .setLevel(dept.getLevel())
                .setSort(dept.getSort())
                .setStatus(dept.getStatus())
                .setUpdateTime(dept.getUpdateTime())
                .setUpdateUser(dept.getUpdateUser())
                .setCreateTime(dept.getCreateTime())
                .setCreateUser(dept.getCreateUser())
                .setChildren(new TreeSet<>());
        return deptDto;
    }
}